#define _GNU_SOURCE
#include <netinet/in.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/if.h>

int create_raw_multi_if(const char *group, int service, struct sockaddr_storage *addr, int proto)
{
	int fd = socket(AF_INET6, SOCK_DGRAM, proto);
	if (fd < 0) {
		perror("socket");
		exit(0);
	}

	memset(addr, 0, sizeof(struct sockaddr_storage));
	struct sockaddr_in6 *maddr = (void *)addr;
	maddr->sin6_family = AF_INET6;
	maddr->sin6_port = htons(service);

	if (inet_pton(AF_INET6, group, &maddr->sin6_addr) != 1) {
		perror("inet_pton");
		exit(0);
	}

	int idx = if_nametoindex("eth3");
	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &idx, sizeof(idx)) < 0) {
		perror("setsockopt");
		exit(0);
	}

	// struct sockaddr_in6 saddr;
	// memset(&saddr, 0, sizeof(saddr));
	// saddr.sin6_family = AF_INET6;
	// if (inet_pton(AF_INET6, "240e:358:906:9100:95f3:db18:3845:c122", &saddr.sin6_addr) != 1) {
	// 	perror("inet_pton");
	// 	exit(0);
	// }

	// if (bind(fd, (void *)&saddr, sizeof(saddr)) < 0) {
	// 	perror("bind");
	// 	exit(0);
	// }

	return fd;
}

void build_srh(struct msghdr *msg)
{
	// int extlen = inet6_rth_space(IPV6_RTHDR_TYPE_0, 3);
	// msg->msg_control = bp;
	// msg->msg_controllen = CMSG_SPACE(extlen);
	// struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
	// cmsg->cmsg_level = IPPROTO_IPV6;
	// cmsg->cmsg_type = IPV6_RTHDR;
	// cmsg->cmsg_len = CMSG_LEN(extlen);

	// void *extptr = CMSG_DATA(cmsg);
	// extptr = inet6_rth_init(extptr, extlen, IPV6_RTHDR_TYPE_0, 3);
	// struct in6_addr addr;
	// inet_pton(AF_INET6, "A0::1", &addr);
	// inet6_rth_add(extptr, &addr);
	// inet_pton(AF_INET6, "A0::2", &addr);
	// inet6_rth_add(extptr, &addr);
	// inet_pton(AF_INET6, "A0::3", &addr);
	// inet6_rth_add(extptr, &addr);
	// void *extptr;
	// socklen_t extlen;
	// struct cmsghdr *cmsgptr;
	// int cmsglen;
	// struct in6_addr addr;

	// extlen = inet6_rth_space(IPV6_RTHDR_TYPE_0, 0);
	// cmsglen = CMSG_SPACE(extlen);
	// cmsgptr = malloc(cmsglen);
	// cmsgptr->cmsg_len = CMSG_LEN(extlen);
	// cmsgptr->cmsg_level = IPPROTO_IPV6;
	// cmsgptr->cmsg_type = IPV6_RTHDR;

	// extptr = CMSG_DATA(cmsgptr);
	// extptr = inet6_rth_init(extptr, extlen, IPV6_RTHDR_TYPE_0, 3);

	// inet_pton(AF_INET6, "A0::1", &addr);
	// inet6_rth_add(extptr, &addr);
	// inet_pton(AF_INET6, "A0::2", &addr);
	// inet6_rth_add(extptr, &addr);
	// inet_pton(AF_INET6, "A0::2", &addr);
	// inet6_rth_add(extptr, &addr);

	// msg->msg_control = cmsgptr;
	// msg->msg_controllen = cmsglen;
}

int main()
{
	struct sockaddr_storage addr;
	int fd = create_raw_multi_if("FF02::8888", 8888, &addr, IPPROTO_UDP);
	char buf[] = "Hello World";
	union {
		char buf[1024];
		struct cmsghdr align;
	} u;

	char iobuf[1024];
	struct iovec iov = { buf, sizeof(buf) };
	struct msghdr msg = {
		.msg_name = &addr,
		.msg_namelen = sizeof(addr),
		.msg_iov = &iov,
		.msg_iovlen = 1,
		.msg_control = u.buf,
		.msg_controllen = 0, //sizeof(u.buf),
		.msg_flags = 0 //
	};

	for (;;) {
		if (sendto(fd, buf, sizeof(buf), 0, (void *)&addr, sizeof(addr)) < 0) {
			perror("sendto");
		}
		if (sendmsg(fd, &msg, 0) < 0) {
			perror("sendmsg");
			exit(0);
		}
		sleep(1);
	}

	return 0;
}